<?php
namespace app\service;

use think\facade\Log;
use think\facade\Config;
use Simps\MQTT\Client;
use Simps\MQTT\Config\ClientConfig;

/**
 * MQTT消息发布服务
 */
class MqttPublisher
{
    private $client;
    private $config;
    
    public function __construct()
    {
        $this->config = Config::get('mqtt');
    }
    
    /**
     * 发布消息到MQTT
     * 
     * @param string $topic 主题
     * @param string $message 消息内容
     * @param int $qos QoS等级
     * @return bool 发布结果
     */
    public function publish(string $topic, string $message, int $qos = 0): bool
    {
        try {
            // 创建MQTT客户端配置
            $clientConfig = new ClientConfig();
            $clientConfig->setHost($this->config['host'])
                        ->setPort($this->config['port'])
                        ->setUsername($this->config['username'])
                        ->setPassword($this->config['password'])
                        ->setClientId($this->generateClientId())
                        ->setKeepAlive($this->config['keepalive'] ?? 60)
                        ->setConnectTimeout($this->config['connect_timeout'] ?? 10)
                        ->setReadWriteTimeout($this->config['read_write_timeout'] ?? 5);

            // 创建客户端
            $this->client = new Client($clientConfig);

            Log::info("MQTT发布器连接中: {$this->config['host']}:{$this->config['port']}");

            // 连接到MQTT服务器
            $connectResult = $this->client->connect();

            if ($connectResult !== true && !is_array($connectResult)) {
                Log::error("MQTT发布器连接失败");
                return false;
            }

            Log::info("MQTT发布器连接成功");

            // 发布消息
            $publishResult = $this->client->publish($topic, $message, $qos);

            if ($publishResult) {
                Log::info("MQTT消息发布成功: 主题={$topic}, QoS={$qos}, 消息长度=" . strlen($message));

                // 记录发布的消息内容（调试用）
                Log::info("发布的消息内容: {$message}");

                return true;
            } else {
                Log::error("MQTT消息发布失败: 主题={$topic}");
                return false;
            }

        } catch (\Throwable $e) {
            Log::error("MQTT发布异常: " . $e->getMessage());
            return false;
        } finally {
            // 断开连接
            if ($this->client) {
                try {
                    $this->client->close();
                    Log::info("MQTT发布器连接已关闭");
                } catch (\Throwable $e) {
                    Log::warning("MQTT发布器关闭连接时异常: " . $e->getMessage());
                }
            }
        }
    }
    
    /**
     * 批量发布消息
     * 
     * @param array $messages 消息数组 [['topic' => '', 'message' => '', 'qos' => 0], ...]
     * @return array 发布结果 ['success' => 成功数量, 'failed' => 失败数量, 'details' => 详细结果]
     */
    public function batchPublish(array $messages): array
    {
        $results = [
            'success' => 0,
            'failed' => 0,
            'details' => []
        ];
        
        try {
            // 创建MQTT客户端配置
            $clientConfig = new ClientConfig();
            $clientConfig->setHost($this->config['host'])
                        ->setPort($this->config['port'])
                        ->setUsername($this->config['username'])
                        ->setPassword($this->config['password'])
                        ->setClientId($this->generateClientId())
                        ->setKeepAlive($this->config['keepalive'] ?? 60)
                        ->setConnectTimeout($this->config['connect_timeout'] ?? 10)
                        ->setReadWriteTimeout($this->config['read_write_timeout'] ?? 5);

            // 创建客户端
            $this->client = new Client($clientConfig);
            
            // 连接到MQTT服务器
            $connectResult = $this->client->connect();
            
            if ($connectResult !== true && !is_array($connectResult)) {
                Log::error("MQTT批量发布器连接失败");
                return $results;
            }
            
            Log::info("MQTT批量发布器连接成功，准备发布 " . count($messages) . " 条消息");
            
            // 逐个发布消息
            foreach ($messages as $index => $msg) {
                try {
                    $topic = $msg['topic'] ?? '';
                    $message = $msg['message'] ?? '';
                    $qos = $msg['qos'] ?? 0;
                    
                    if (empty($topic) || empty($message)) {
                        $results['failed']++;
                        $results['details'][] = [
                            'index' => $index,
                            'success' => false,
                            'error' => '主题或消息为空'
                        ];
                        continue;
                    }
                    
                    $publishResult = $this->client->publish($topic, $message, $qos);
                    
                    if ($publishResult) {
                        $results['success']++;
                        $results['details'][] = [
                            'index' => $index,
                            'topic' => $topic,
                            'success' => true
                        ];
                        
                        Log::info("批量发布成功: 主题={$topic}");
                    } else {
                        $results['failed']++;
                        $results['details'][] = [
                            'index' => $index,
                            'topic' => $topic,
                            'success' => false,
                            'error' => '发布失败'
                        ];
                        
                        Log::error("批量发布失败: 主题={$topic}");
                    }
                    
                } catch (\Throwable $e) {
                    $results['failed']++;
                    $results['details'][] = [
                        'index' => $index,
                        'success' => false,
                        'error' => $e->getMessage()
                    ];
                    
                    Log::error("批量发布异常: " . $e->getMessage());
                }
            }
            
        } catch (\Throwable $e) {
            Log::error("MQTT批量发布异常: " . $e->getMessage());
        } finally {
            // 断开连接
            if ($this->client) {
                try {
                    $this->client->close();
                    Log::info("MQTT批量发布器连接已关闭");
                } catch (\Throwable $e) {
                    Log::warning("MQTT批量发布器关闭连接时异常: " . $e->getMessage());
                }
            }
        }
        
        return $results;
    }
    
    /**
     * 生成客户端ID
     * 
     * @return string
     */
    private function generateClientId(): string
    {
        return 'publisher_' . uniqid() . '_' . getmypid();
    }
    
    /**
     * 测试MQTT连接
     *
     * @return bool
     */
    public function testConnection(): bool
    {
        try {
            $clientConfig = new ClientConfig();
            $clientConfig->setHost($this->config['host'])
                        ->setPort($this->config['port'])
                        ->setUsername($this->config['username'])
                        ->setPassword($this->config['password'])
                        ->setClientId($this->generateClientId())
                        ->setConnectTimeout(5);

            $client = new Client($clientConfig);
            $result = $client->connect();

            if ($result === true || is_array($result)) {
                $client->close();
                return true;
            }

            return false;

        } catch (\Throwable $e) {
            Log::error("MQTT连接测试失败: " . $e->getMessage());
            return false;
        }
    }
}
